
import os
import subprocess
import sys
import threading
import pystray
import os
import logging
import time
from datetime import datetime
from PIL import Image
import shutil
from datetime import timedelta

#导入更改进程名相关库
#import os
#from setproctitle import setproctitle

# 全局变量用于存储日志文件路径
info_log_path = None
# 配置日志
logger = None

def setup_logging():
    """配置INFO日志，创建当前日期的日志文件"""
    try:
        base_log_dir = "DaemonLog"
        now = datetime.now()
        
        # 使用当前日期创建目录结构
        year = now.strftime("%Y")
        month = now.strftime("%m")
        day = now.strftime("%d")
        
        # 创建目录结构：DaemonLog/INFO/YYYY/MM/DD/
        day_dir = os.path.join(base_log_dir, "INFO", year, month, day)
        os.makedirs(day_dir, exist_ok=True)
        
        # 创建带时间戳的日志文件名
        timestamp = now.strftime("%Y%m%d_%H-%M-%S")
        info_log = os.path.join(day_dir, f"daemon_{timestamp}.log")
        
        # 配置日志器
        logger = logging.getLogger()
        logger.setLevel(logging.INFO)

        # 清除已存在的处理器
        if logger.handlers:
            logger.handlers.clear()

        # 创建文件处理器
        info_handler = logging.FileHandler(info_log, encoding='utf-8')
        info_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
        info_handler.setFormatter(info_formatter)
        logger.addHandler(info_handler)

        # 更新全局日志路径
        global info_log_path
        info_log_path = info_log

        return logger, info_log
    except Exception as e:
        print(f"配置日志时发生错误: {e}")
        import traceback
        traceback.print_exc()
        return None, None

def reset_logging():
    """每天0:00自动重新配置日志，创建新一天的日志文件"""
    global logger, info_log_path
    try:
        old_log_path = info_log_path
        now = datetime.now()
        
        print(f"开始创建{now.strftime('%Y-%m-%d')}的新日志文件...")
        new_logger, new_log_path = setup_logging()
        
        # 检查setup_logging是否成功
        if new_logger is None or new_log_path is None:
            print("创建新日志文件失败")
            # 如果配置失败，使用原logger记录错误
            if logger and logger.handlers:
                logger.error(f"创建{now.strftime('%Y-%m-%d')}的新日志文件失败")
            return logger
        
        # 更新全局logger和日志路径
        logger = new_logger
        info_log_path = new_log_path
        
        # 记录新日志文件创建成功
        logger.info("=" * 60)
        logger.info(f"新一天日志文件创建成功: {now.strftime('%Y-%m-%d')}")
        logger.info(f"新日志文件: {new_log_path}")
        if old_log_path:
            logger.info(f"旧日志文件: {old_log_path}")
        
        # 立即执行目录清理
        def clean_old_files_daily(base_dir, days_threshold):
            """每日清理指定目录下超过指定天数的文件"""
            if not os.path.exists(base_dir):
                return 0
            now = datetime.now()
            cleaned_count = 0
            for root, dirs, files in os.walk(base_dir):
                for file in files:
                    file_path = os.path.join(root, file)
                    try:
                        # 获取文件最后修改时间
                        mtime = datetime.fromtimestamp(os.path.getmtime(file_path))
                        if (now - mtime) > timedelta(days=days_threshold):
                            os.remove(file_path)
                            cleaned_count += 1
                            logger.info(f"已清理旧文件: {file_path}")
                    except Exception as e:
                        logger.warning(f"清理文件{file_path}失败: {e}")
                # 清理空目录
                if not os.listdir(root) and root != base_dir:
                    try:
                        os.rmdir(root)
                        logger.info(f"已清理空目录: {root}")
                    except Exception as e:
                        logger.warning(f"清理空目录{root}失败: {e}")
            return cleaned_count
        
        # 执行清理任务
        logger.info("开始执行每日清理任务...")
        
        # 清理日志文件（60天）
        log_dirs = ["AppLog", "DaemonLog", "AutoPlayBellLog"]
        total_cleaned = 0
        for log_dir in log_dirs:
            cleaned = clean_old_files_daily(log_dir, 60)
            total_cleaned += cleaned
            logger.info(f"已清理 {log_dir} 目录 {cleaned} 个60天前日志文件")
        
        # 清理音频文件（14天）
        audio_dirs = ["voice", "music"]
        for audio_dir in audio_dirs:
            cleaned = clean_old_files_daily(audio_dir, 14)
            total_cleaned += cleaned
            logger.info(f"已清理 {audio_dir} 目录 {cleaned} 个14天前音频文件")
        
        logger.info(f"本次共清理 {total_cleaned} 个旧文件")
        logger.info("=" * 60)
        
        return new_logger
    except Exception as e:
        print(f"创建新日志文件时发生错误: {e}")
        import traceback
        traceback.print_exc()
        # 如果重配置失败，使用原logger记录错误
        if logger and logger.handlers:
            logger.error(f"创建新日志文件失败: {e}")
        return logger


def create_level_log(logger, level, message, trace=None):
    """创建WARNING或ERROR日志"""
    if logger is None:
        return

    base_log_dir = "DaemonLog"
    dir_name = "WARNING" if level == logging.WARNING else "ERROR"
    dir_path = os.path.join(base_log_dir, dir_name)
    os.makedirs(dir_path, exist_ok=True)

    timestamp = datetime.now().strftime("%Y%m%d_%H-%M-%S_%f")
    log_file = os.path.join(dir_path, f"{timestamp}.log")

    handler = logging.FileHandler(log_file, encoding='utf-8')
    formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    if level == logging.WARNING:
        logger.warning(message)
    else:
        logger.error(message)
        if trace:
            logger.error(trace)

    logger.removeHandler(handler)


def open_log_directory():
    """打开日志目录"""
    if info_log_path and os.path.exists(os.path.dirname(info_log_path)):
        # 在Windows上打开文件夹
        subprocess.Popen(["explorer.exe", os.path.dirname(info_log_path)])
    elif os.path.exists("DaemonLog"):
        subprocess.Popen(["explorer.exe", "DaemonLog"])


# 全局变量用于控制程序退出
running = True
log_reset_running = True

def start_app(logger):
    """启动app.py"""
    try:
        subprocess.Popen(["wscript.exe", "app.vbs"], creationflags=subprocess.SW_HIDE)
        logger.info("已启动app.py")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"启动app.py失败: {e}")

def start_autoplay(logger):
    """启动AutoPlayBell.py"""
    try:
        subprocess.Popen(["wscript.exe", "AutoPlayBell.vbs"], creationflags=subprocess.SW_HIDE)
        logger.info("已启动AutoPlayBell.py")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"启动AutoPlayBell.py失败: {e}")

def start_player(logger, filename=None, volume=None):
    """启动带参数的BellPlayer.py"""
    if filename is None or volume is None:
        # 如果参数不完整，通过open_input_window处理
        open_input_window(logger)
        return
    try:
        subprocess.Popen([
            "./runtime/python.exe", 
            "BellPlayer.py", 
            "-f", filename, 
            "-v", volume
        ], creationflags=subprocess.CREATE_NEW_CONSOLE)
        logger.info(f"已启动BellPlayer.py播放铃声: {filename}，音量: {volume}")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"启动BellPlayer.py失败: {e}")


def start_frp(logger):
    """启动frp"""
    try:
        # 检查是否已有frpc进程在运行
        result = subprocess.run(["tasklist", "/FI", "IMAGENAME eq frpc.exe"], capture_output=True, text=True)
        if "frpc.exe" not in result.stdout:
            # 启动frpc
            frpc_path = os.path.join("frpc", "frpc.vbs")
            # 以./frpc路径运行
            subprocess.Popen(["wscript.exe", os.path.basename(frpc_path)], cwd=os.path.dirname(frpc_path), creationflags=subprocess.SW_HIDE)
            logger.info("已启动frpc")
        else:
            logger.info("frpc进程已在运行中")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"启动frp失败: {e}")

def start_all(logger):
    """同时启动主程序和管理网页"""
    try:
        subprocess.Popen(["wscript.exe", "app.vbs"], creationflags=subprocess.SW_HIDE)
        subprocess.Popen(["wscript.exe", "AutoPlayBell.vbs"], creationflags=subprocess.SW_HIDE)
        # 启动frp
        start_frp(logger)
        logger.info("已同时启动主程序和管理网页及frp")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"启动主程序和管理网页失败: {e}")


def open_input_window(logger):
    """打开输入参数窗口"""
    try:
        # 创建一个新的命令行窗口运行BellPlayer.py
        subprocess.Popen(["./runtime/python.exe", "BellPlayer.py"],
                        creationflags=subprocess.CREATE_NEW_CONSOLE)
        logger.info("已打开BellPlayer参数输入窗口")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"打开BellPlayer参数输入窗口失败: {e}")


def log_reset_worker():
    """后台线程：每天0:00自动重新配置日志，创建新一天的日志文件"""
    global logger, log_reset_running
    last_reset_date = None
    while log_reset_running:
        try:
            now = datetime.now()
            current_date = now.date()
            
            # 检查是否为0:00且当天还未重置过日志
            if now.hour == 0 and now.minute == 0 and last_reset_date != current_date:
                logger.info("=" * 60)
                logger.info(f"检测到0:00，开始创建新一天日志文件: {now.strftime('%Y-%m-%d %H:%M:%S')}")
                
                # 记录旧日志路径
                old_log_path = info_log_path
                
                # 重新配置日志，创建新一天的日志文件
                new_logger = reset_logging()
                
                if new_logger:
                    logger = new_logger
                    last_reset_date = current_date
                    logger.info(f"新日志文件已创建: {info_log_path}")
                    if old_log_path:
                        logger.info(f"旧日志文件: {old_log_path}")
                    logger.info("新一天日志文件创建完成")
                else:
                    logger.error("创建新日志文件失败，继续使用当前日志")
                
                logger.info("=" * 60)
                
                # 休眠65秒确保不会重复触发（0:00:00到0:01:05之间不会重复）
                time.sleep(65)
            else:
                # 每分钟检查一次
                time.sleep(60)
        except Exception as e:
            if logger and logger.handlers:
                logger.error(f"日志重置线程错误: {e}")
            time.sleep(60)

def start_log_reset_thread():
    """启动日志重置线程"""
    thread = threading.Thread(target=log_reset_worker, daemon=True)
    thread.start()
    return thread

def on_quit(icon, item, logger):
    """退出守护进程"""
    global running, log_reset_running
    running = False
    log_reset_running = False
    icon.stop()
    logger.info("用户请求退出守护进程")


def force_quit(icon, item, logger):
    """强退出守护进程及所有相关程序"""
    global running
    running = False
    icon.stop()
    try:
        # 记录强退出日志
        logger.info("用户请求强退出守护进程及所有相关程序")
        
        # 在新的命令提示符窗口中执行进程结束命令
        try:
            # 构建要执行的命令字符串
            cmd_command = (
                'start exit.vbs'
            )
            
            # 执行命令
            subprocess.Popen(cmd_command, shell=True)
            subprocess.Popen(cmd_command, shell=True)
            logger.info("已启动新命令窗口执行进程结束命令")
        except Exception as e:
            create_level_log(logger, logging.ERROR, f"启动命令窗口失败: {e}")
        
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"强退出过程中发生错误: {e}")


def open_version_file():    
    """打开version.txt文件"""
    try:
        os.startfile("./version.txt")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"打开version.txt失败: {e}")

def open_gitee_repo():
    """打开Gitee仓库"""
    try:
        import webbrowser
        webbrowser.open("https://gitee.com/zzrcmd/auto-class-bell-player/")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"打开Gitee仓库失败: {e}")

def restart_frp(logger):
    """重新启动frp"""
    try:
        # 结束frpc进程
        subprocess.run(["taskkill", "/F", "/IM", "frpc.exe"], capture_output=True, text=True)
        logger.info("已结束frpc进程")
        
        # 启动frpc
        frpc_path = os.path.join("frpc", "frpc.vbs")
        # 以./frpc路径运行
        subprocess.Popen(["wscript.exe", os.path.basename(frpc_path)], cwd=os.path.dirname(frpc_path), creationflags=subprocess.SW_HIDE)
        logger.info("已重新启动frpc")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"重新启动frp失败: {e}")

def stop_frp(logger):
    """结束frpc进程"""
    try:
        # 结束frpc进程
        result = subprocess.run(["taskkill", "/F", "/IM", "frpc.exe"], capture_output=True, text=True)
        if result.returncode == 0:
            logger.info("已成功结束frpc进程")
        else:
            logger.info("没有正在运行的frpc进程")
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"结束frpc进程失败: {e}")

def create_tray_icon(logger):
    """创建托盘图标"""
    try:
        # 加载图标
        image = Image.open("./icon/daemon.ico")
        
        # 读取版本号
        version = "未知版本"
        try:
            with open("./version.txt", "r") as f:
                version = f.readline().strip()
        except Exception as e:
            create_level_log(logger, logging.ERROR, f"读取version.txt失败: {e}")
        
        # 创建菜单
        menu = (
            pystray.MenuItem(f"当前版本号：{version}", lambda: open_version_file()),
            pystray.MenuItem("打开gitee仓库", lambda: open_gitee_repo()),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("打开运行日志", lambda: open_log_directory()),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("启动管理网页", lambda: start_app(logger)),
            pystray.MenuItem("启动自动播放铃声系统", lambda: start_autoplay(logger)),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("一键启动主程序和管理网页", lambda: start_all(logger)),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("重新启动frp", lambda: restart_frp(logger)),
            pystray.MenuItem("结束frpc进程", lambda: stop_frp(logger)),
            pystray.Menu.SEPARATOR,
            pystray.MenuItem("退出守护进程", lambda icon, item: on_quit(icon, item, logger)),
            pystray.MenuItem("强退出守护进程及主程序、管理网页、铃声播放、frpc进程", lambda icon, item: force_quit(icon, item, logger)),
        )
        
        # 创建图标对象
        icon = pystray.Icon("daemon", image, "铃声系统守护进程", menu)
        
        # 运行图标
        icon.run()
    except Exception as e:
        create_level_log(logger, logging.ERROR, f"创建托盘图标失败: {e}")
        pass


def main():
    """主函数"""
    global logger
    print("=== 守护进程启动 ===" )

    def clean_old_files(base_dir, days_threshold):
        """清理指定目录下超过指定天数的文件"""
        if not os.path.exists(base_dir):
            print(f"目录不存在: {base_dir}")
            return
        now = datetime.now()
        for root, dirs, files in os.walk(base_dir):
            for file in files:
                file_path = os.path.join(root, file)
                try:
                    # 获取文件最后修改时间
                    mtime = datetime.fromtimestamp(os.path.getmtime(file_path))
                    if (now - mtime) > timedelta(days=days_threshold):
                        os.remove(file_path)
                        if logger and logger.handlers:
                            logger.info(f"已清理旧文件: {file_path}")
                        else:
                            print(f"已清理旧文件: {file_path}")
                except Exception as e:
                    if logger and logger.handlers:
                        logger.warning(f"清理文件{file_path}失败: {e}")
                    else:
                        print(f"清理文件{file_path}失败: {e}")
            # 清理空目录（可选）
            if not os.listdir(root):
                try:
                    os.rmdir(root)
                    if logger and logger.handlers:
                        logger.info(f"已清理空目录: {root}")
                    else:
                        print(f"已清理空目录: {root}")
                except Exception as e:
                    if logger and logger.handlers:
                        logger.warning(f"清理空目录{root}失败: {e}")
                    else:
                        print(f"清理空目录{root}失败: {e}")

    try:
        # 配置日志
        print("开始配置日志系统...")
        logger, log_path = setup_logging()
        
        # 检查日志是否配置成功
        if logger is None:
            print("日志系统配置失败！将使用控制台输出")
        else:
            print(f"日志系统配置成功，日志路径: {log_path}")
            logger.info("守护进程已启动")
        
        # 检查启动时是否为0:00，如果是则立即重新配置日志
        now = datetime.now()
        print(f"当前时间: {now.strftime('%Y-%m-%d %H:%M:%S')}")
        if now.hour == 0 and now.minute == 0:
            print("启动时间为0:00，立即重新配置日志...")
            if logger:
                logger.info("启动时间为0:00，立即重新配置日志...")
            new_logger = reset_logging()
            if new_logger:
                logger = new_logger

        # 清理60天前的日志文件
        log_dirs = ["AppLog", "DaemonLog", "AutoPlayBellLog"]
        print("开始清理60天前的日志文件...")
        for log_dir in log_dirs:
            clean_old_files(log_dir, 60)
            if logger and logger.handlers:
                logger.info(f"已完成{log_dir}目录60天前日志清理")
            else:
                print(f"已完成{log_dir}目录60天前日志清理")

        # 清理14天前的音频文件
        audio_dirs = ["voice", "music"]
        print("开始清理14天前的音频文件...")
        for audio_dir in audio_dirs:
            clean_old_files(audio_dir, 14)
            if logger and logger.handlers:
                logger.info(f"已完成{audio_dir}目录14天前音频文件清理")
            else:
                print(f"已完成{audio_dir}目录14天前音频文件清理")
        
        # 静默启动主程序和管理网页
        print("开始启动主程序和管理网页...")
        start_all(logger)
        if logger and logger.handlers:
            logger.info("已静默启动主程序和管理网页")
        else:
            print("已静默启动主程序和管理网页")
        
        # 启动日志重置线程
        print("启动日志重置线程...")
        log_reset_thread = start_log_reset_thread()
        if logger and logger.handlers:
            logger.info("日志重置线程已启动")
        else:
            print("日志重置线程已启动")
        
        # 创建并启动托盘图标线程
        print("创建并启动托盘图标线程...")
        tray_thread = threading.Thread(target=lambda: create_tray_icon(logger), daemon=True)
        tray_thread.start()
        if logger and logger.handlers:
            logger.info("托盘图标线程已启动")
        else:
            print("托盘图标线程已启动")
        
        # 保持主程序运行
        print("守护进程已成功启动，开始主循环...")
        while running:
            time.sleep(1)
    except Exception as e:
        print(f"发生严重错误: {e}")
        import traceback
        traceback.print_exc()
        if logger and logger.handlers:
            logger.error(f"发生错误: {e}")
            create_level_log(logger, logging.ERROR, f"发生错误: {e}")
    finally:
        print("守护进程已退出")
        if logger and logger.handlers:
            logger.info("守护进程已退出")

if __name__ == "__main__":
    # 设置进程名称
    #setproctitle('gbz_daemon')
    main()
